#pragma once
#include <iostream>
#include <sys/select.h>
#include "Common.hpp"
#include "InetAddr.hpp"
#include "Log.hpp"
#include "Socket.hpp"

using namespace LogModule;

class SelectServer{

	const static int size = sizeof(fd_set) * 8;
	const static int defaultfd = -1;

public:

	SelectServer(uint16_t port){
		_listensock = std::make_unique<TcpSocket>();
		_listensock->BulidTcpSocketMethod(port);
		
		_isrunning = false;
		for(int i = 0; i < size; i++){
			_fd_array[i] = defaultfd;
		}
		_fd_array[0] = _listensock->GetFd();
	}

	void Start(){
		_isrunning = true;
		while(_isrunning){
			fd_set rfds;
			FD_ZERO(&rfds); // 清空rfds集合
			int maxfd = _fd_array[0];
			for(int i = 0; i < size; i++){
				if(_fd_array[i] == defaultfd) 
					continue;
				
				FD_SET(_fd_array[i], &rfds); // 将有效的套接字加入rfds集合
				if(_fd_array[i] > maxfd)
					maxfd = _fd_array[i]; // 更新最大套接字
			}

			Printfd();

			int ret = select(maxfd + 1, &rfds, nullptr, nullptr, nullptr);
			switch(ret){
				case -1:
					LOG(LogLevel::ERROR) << "select error";
					break;
				case 0:
					LOG(LogLevel::WARNING) << "select timeout";
					break;
				default:
					Dispatch(rfds);
					break;
			}
		}

	}

	void Dispatch(fd_set& rfds){ 
		for(int i = 0; i < size; i++){
			if(_fd_array[i] == defaultfd)
				continue;
			
				if(FD_ISSET(_fd_array[i], &rfds)){
					if(_fd_array[i] == _listensock->GetFd()){
						// 监听套接字
						Accepter();
					}
					else{
						// 数据套接字
						Receiver(_fd_array[i]);
					}	
				}
		}
	}

	void Accepter(){
		InetAddr client;
		int fd = _listensock->Accept(&client);
		if(fd < 0){
			LOG(LogLevel::ERROR) << "accept error";
			return;
		}

		// 将新的套接字加入数组
		int pos = 0;
		for(int i = 1; i < size; i++){
			if(_fd_array[i] == defaultfd){
				pos = i;
				break;
			}
		}

		// 插入新的套接字
		if(pos != 0)
			_fd_array[pos] = fd;
		else{
			LOG(LogLevel::ERROR) << "_fd_array is full";
			close(fd);
		}
	}

	void Receiver(int fd){
		char buffer[1024];
		int ret = recv(fd, buffer, sizeof(buffer)-1, 0);
		if(ret > 0){
			buffer[ret] = 0;
			std::cout<<buffer<<std::endl;
		}
		else if(ret == 0){
			// 对端关闭
			LOG(LogLevel::INFO) << "client close";
			close(fd);
			// 清除文件描述符
			for(int i = 0; i < size; i++){
				if(_fd_array[i] == fd){
					_fd_array[i] = defaultfd;
					break;
				}
			}
		}
		else{
			LOG(LogLevel::ERROR) << "recv error";
			close(fd);
			for(int i = 0; i < size; i++){
				if(_fd_array[i] == fd){
					_fd_array[i] = defaultfd;
					break;
				}
			}
		}
	}

	void Stop(){
		_isrunning = false;
	}

	void Printfd(){
		std::cout<<"_fd_array: ";
		for(int i = 0; i < size; i++){
			if(_fd_array[i] != defaultfd)
				std::cout<<_fd_array[i]<<" ";
		}
		std::cout<<std::endl;
	}
	~SelectServer(){}


private:
	std::unique_ptr<Socket> _listensock;
	bool _isrunning;
	int _fd_array[size];
};